﻿//
// (C) Copyright 2009 Irantha Suwandarathna (iranthas@hotmail.com)
// All rights reserved.
//


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using Microsoft.Win32;
using System.IO;
using System.Xml;

namespace EffiProzDBProvider
{
    [RunInstaller(true)]
    public partial class InstallerCustomTasks : System.Configuration.Install.Installer
    {
        private static Guid standardDataProviderGuid = new Guid("{1b5ac345-1e07-4800-822e-d40acebdf9dc}");
        private static Guid standardDataSourcesGuid = new Guid("{28ee5269-ec53-4492-b05b-fac991b98fbe}");

        private static Guid standardCFDataSourcesGuid = new Guid("{0EBAAB6E-CA80-4b4a-8DDF-CBE6BF058C72}");
        private static Guid oledbDataProviderGuid = new Guid("{7F041D59-D76A-44ed-9AA2-FBF6B0548B80}");
        private static Guid oledbAltDataProviderGuid = new Guid("{7F041D59-D76A-44ed-9AA2-FBF6B0548B81}");
        private static Guid jetDataSourcesGuid = new Guid("{466CE797-67A4-4495-B75C-A3FD282E7FC3}");
        private static Guid jetAltDataSourcesGuid = new Guid("{466CE797-67A4-4495-B75C-A3FD282E7FC4}");

        private Dictionary<string, string> _regRoots = new Dictionary<string, string>();
        private List<string> _frameworks = new List<string>();
    

        public InstallerCustomTasks() :base()
        {
            
        }


        private void InitFrameworks()
        {
            RegistryKey key;
            string frameworkpath;

            using (key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\.NETFramework"))
            {
                frameworkpath = key.GetValue("InstallRoot") as string;
            }

            string[] frameworkfolders = Directory.GetDirectories(frameworkpath);
            foreach (string framework in frameworkfolders)
            {
                if (File.Exists(Path.Combine(framework, "CONFIG\\machine.config")))
                    _frameworks.Add(Path.GetFileName(framework));
            }
        }

        private void InstallDesigner()
        {
            RegistryKey key;           
           
            _regRoots.Add("9.0", "2008");

            foreach (KeyValuePair<string, string> pair in _regRoots)
            {
                using (key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft"))
                {
                    AddRemoveItem(key, pair.Key, "VisualStudio", String.Format("Visual Studio {0} (full editions)", pair.Value), standardDataProviderGuid, false);                    
                    
                }
                //GlobalAddRemove(pair.Key);
            }
        }

        private void UninstallDesigner()
        {
            RegistryKey key;

            _regRoots.Add("9.0", "2008");

            foreach (KeyValuePair<string, string> pair in _regRoots)
            {
                using (key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft"))
                {
                    AddRemoveItem(key, pair.Key, "VisualStudio", String.Format("Visual Studio {0} (full editions)", pair.Value), standardDataProviderGuid, true);

                }
                //GlobalAddRemove(pair.Key);
            }

        }



        private bool AddRemoveItem(RegistryKey parent, string version, string subkeyname, string itemName, Guid lookFor,
            Boolean isRemove)
        {
            RegistryKey subkey;

            try
            {
                using (subkey = parent.OpenSubKey(String.Format("{0}\\{1}", subkeyname, version)))
                {
                    // Verify this edition has been installed and its not a fluke that the key exists
                    string dir = (string)subkey.GetValue("InstallDir");

                    using (RegistryKey subsubkey = subkey.OpenSubKey("Packages"))
                    {
                        if (subsubkey == null)
                            throw new ArgumentException("Edition not installed");
                        if (subsubkey.SubKeyCount < 5)
                            throw new ArgumentException("Edition not installed");
                    }

                    using (RegistryKey subsubkey = subkey.OpenSubKey("DataProviders"))
                    {
                        if (subsubkey == null)
                            throw new ArgumentException("Edition not installed");
                    }

                    using (RegistryKey subsubkey = subkey.OpenSubKey(String.Format("DataProviders\\{0}",  lookFor.ToString("B") )))
                    {     
                        if(isRemove)
                            UninstallVS(subkeyname, version, standardDataProviderGuid, standardDataSourcesGuid); 
                        else
                            InstallVS(subkeyname, version, standardDataProviderGuid, standardDataSourcesGuid);                       
                    }
                    
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }

        private void UninstallVS(string keyname, string version, Guid provider, Guid source)
        {
            try
            {
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\DataProviders", keyname, version), true))
                {
                    if (key != null) key.DeleteSubKeyTree(provider.ToString("B"));
                }
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\DataSources", keyname, version), true))
                {
                    if (key != null) key.DeleteSubKeyTree(source.ToString("B"));
                }

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Packages", keyname, version), true))
                {
                    if (key != null) key.DeleteSubKeyTree("{2d0231d8-582c-4350-aec8-12723c846ef6}");
                }

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Services", keyname, version), true))
                {
                    if (key != null) key.DeleteSubKeyTree("{3b64b149-4956-48f3-a24d-a76916a915d7}");
                }

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Menus", keyname, version), true))
                {
                    key.DeleteValue("{2d0231d8-582c-4350-aec8-12723c846ef6}");
                }
            }
            catch (Exception)
            { }
        }


        private void InstallVS(string keyname, string version, Guid provider, Guid source)
        {
            bool usePackage = (keyname == "VisualStudio");
            string path = Path.GetDirectoryName( typeof(InstallerCustomTasks).Assembly.Location);
            path = Path.Combine(path, "EffiProz.Designer.dll");
           // path = @"C:\Users\irantha\Documents\Visual Studio 10\Projects\New Folder\EffiProz\EffiProzDesigner\bin\Debug\EffiProz.Designer.dll";

            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\DataProviders", keyname, version), true))
            {
                using (RegistryKey subkey = key.CreateSubKey(provider.ToString("B"), RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                   

                    subkey.SetValue(null, ".NET Framework Data Provider for EffiProz");
                    subkey.SetValue("InvariantName", "System.Data.EffiProzDB");
                    subkey.SetValue("Technology", "{77AB9A9D-78B9-4ba7-91AC-873F5338F1D2}");
                    subkey.SetValue("CodeBase", path);


                    if (usePackage)
                        subkey.SetValue("FactoryService", "{3b64b149-4956-48f3-a24d-a76916a915d7}");

                    using (RegistryKey subsubkey = subkey.CreateSubKey("SupportedObjects", RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        using (RegistryKey subsubsubkey = subsubkey.CreateSubKey("DataConnectionUIControl", RegistryKeyPermissionCheck.ReadWriteSubTree))
                        {
                            if (!usePackage)
                                subsubsubkey.SetValue(null, "EffiProz.Designer.EffiProzConnectionUIControl");
                        }
                        using (RegistryKey subsubsubkey = subsubkey.CreateSubKey("DataConnectionProperties", RegistryKeyPermissionCheck.ReadWriteSubTree))
                        {
                            if (!usePackage)
                                subsubsubkey.SetValue(null, "EffiProz.Designer.EffiProzConnectionProperties");
                        }

                        subsubkey.CreateSubKey("DataObjectSupport").Close();
                        subsubkey.CreateSubKey("DataViewSupport").Close();
                        using (RegistryKey subsubsubkey = subsubkey.CreateSubKey("DataConnectionSupport", RegistryKeyPermissionCheck.ReadWriteSubTree))
                        {
                            if (!usePackage)
                                subsubsubkey.SetValue(null, "EffiProz.Designer.EffiProzConnectionSupport");
                        }
                    }
                }
            }

            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\DataSources", keyname, version), true))
            {
                using (RegistryKey subkey = key.CreateSubKey(source.ToString("B"), RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                    subkey.SetValue(null, "EffiProz Database");
                    using (RegistryKey subsubkey = subkey.CreateSubKey("SupportingProviders", RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        subsubkey.CreateSubKey(provider.ToString("B")).Close();
                    }
                }
            }


            if (usePackage)
            {
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Packages", keyname, version), true))
                {
                    using (RegistryKey subkey = key.CreateSubKey("{2d0231d8-582c-4350-aec8-12723c846ef6}", RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        subkey.SetValue(null, "EffiProz Designer Package");
                        subkey.SetValue("Class", "EffiProz.Designer.EffiProzDesignerPackage");
                        subkey.SetValue("CodeBase", path);
                        subkey.SetValue("ID", 400);
                        subkey.SetValue("InprocServer32", "mscoree.dll");
                        subkey.SetValue("CompanyName", "EffiProz (Pvt) Ltd");
                        subkey.SetValue("MinEdition", "standard");
                        subkey.SetValue("ProductName", "EffiProz Data Provider");
                        subkey.SetValue("ProductVersion", "1.0");
                        using (RegistryKey toolboxKey = subkey.CreateSubKey("Toolbox"))
                        {
                            toolboxKey.SetValue("Default Items", 3);
                        }
                    }
                }

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Menus", keyname, version), true))
                {
                    key.SetValue("{2d0231d8-582c-4350-aec8-12723c846ef6}", ", 1000, 3");
                }

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\{0}\\{1}\\Services", keyname, version), true))
                {
                    using (RegistryKey subkey = key.CreateSubKey("{3b64b149-4956-48f3-a24d-a76916a915d7}", RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        subkey.SetValue(null, "{2d0231d8-582c-4350-aec8-12723c846ef6}");
                        subkey.SetValue("Name", "EffiProz Provider Object Factory");
                    }
                }
            }
        }




        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);

            try
            {
                InitFrameworks();

                foreach (string framework in _frameworks)
                {
                    Registry.LocalMachine.DeleteSubKey(String.Format("Software\\Microsoft\\.NETFramework\\{0}\\AssemblyFoldersEx\\EffiProzDB", framework));
                }

                for (int n = 0; n < 2; n++)
                {
                    try
                    {
                        foreach (string framework in _frameworks)
                        {
                            // Remove any entries in the machine.config if they're still there
                            string xmlFileName = Environment.ExpandEnvironmentVariables(String.Format("%WinDir%\\Microsoft.NET\\{0}\\{1}\\CONFIG\\machine.config", (n == 0) ? "Framework" : "Framework64", framework));
                            XmlDocument xmlDoc = new XmlDocument();
                            xmlDoc.PreserveWhitespace = true;
                            xmlDoc.Load(xmlFileName);

                            XmlNode xmlNode = xmlDoc.SelectSingleNode("configuration/system.data/DbProviderFactories/add[@invariant=\"System.Data.EffiProzDB\"]");

                            if (xmlNode != null)
                                xmlNode.ParentNode.RemoveChild(xmlNode);

                            xmlNode = xmlDoc.SelectSingleNode("configuration/system.data/DbProviderFactories/remove[@invariant=\"System.Data.EffiProzDB\"]");
                            if (xmlNode != null)
                                xmlNode.ParentNode.RemoveChild(xmlNode);

                            xmlDoc.Save(xmlFileName);
                        }
                    }
                    catch
                    {
                    }
                }

                UninstallDesigner();
            }
            catch (Exception)
            {
            }           

        }


        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }


        public override void Install(IDictionary savedState)
        {
            base.Install(savedState);

            // Context.LogMessage("EffiProzDB Installer Commit start");
            //System.Diagnostics.Debugger.Break();
            InitFrameworks();


            string path = Path.GetDirectoryName(typeof(InstallerCustomTasks).Assembly.Location);
            

            foreach (string framework in _frameworks)
            {
                try
                {
                    using (RegistryKey key = Registry.LocalMachine.CreateSubKey(String.Format("Software\\Microsoft\\.NETFramework\\{0}\\AssemblyFoldersEx\\EffiProzDB", framework), RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        key.SetValue(null, path);
                    }
                }
                catch (Exception) { }
            }

            for (int n = 0; n < 2; n++)
            {
                foreach (string framework in _frameworks)
                {
                    // Add factory support to the machine.config file.
                    try
                    {
                        string xmlFileName = Environment.ExpandEnvironmentVariables(String.Format("%WinDir%\\Microsoft.NET\\{0}\\{1}\\CONFIG\\machine.config", (n == 0) ? "Framework" : "Framework64", framework));
                        XmlDocument xmlDoc = new XmlDocument();
                        xmlDoc.PreserveWhitespace = true;
                        xmlDoc.Load(xmlFileName);


                        XmlNode xmlNode = xmlDoc.SelectSingleNode("configuration/system.data/DbProviderFactories/add[@invariant=\"System.Data.EffiProzDB\"]");
                        if (xmlNode == null)
                        {
                            XmlNode xmlConfig = xmlDoc.SelectSingleNode("configuration");
                            if (xmlConfig != null)
                            {
                                XmlNode xmlData = xmlConfig.SelectSingleNode("system.data");
                                if (xmlData == null)
                                {
                                    xmlData = xmlDoc.CreateNode(XmlNodeType.Element, "system.data", "");
                                    xmlConfig.AppendChild(xmlData);
                                }
                                XmlNode xmlParent = xmlData.SelectSingleNode("DbProviderFactories");
                                if (xmlParent == null)
                                {
                                    xmlParent = xmlDoc.CreateNode(XmlNodeType.Element, "DbProviderFactories", "");
                                    xmlData.AppendChild(xmlParent);
                                }

                                //xmlNode = xmlDoc.CreateNode(XmlNodeType.Element, "remove", "");
                                //xmlNode.Attributes.SetNamedItem(xmlDoc.CreateAttribute("invariant"));
                                //xmlParent.AppendChild(xmlNode);
                                //xmlNode.Attributes.GetNamedItem("invariant").Value = "System.Data.SQLite";

                                xmlNode = xmlDoc.CreateNode(XmlNodeType.Element, "add", "");
                                xmlNode.Attributes.SetNamedItem(xmlDoc.CreateAttribute("name"));
                                xmlNode.Attributes.SetNamedItem(xmlDoc.CreateAttribute("invariant"));
                                xmlNode.Attributes.SetNamedItem(xmlDoc.CreateAttribute("description"));
                                xmlNode.Attributes.SetNamedItem(xmlDoc.CreateAttribute("type"));
                                xmlParent.AppendChild(xmlNode);
                            }
                        }

                        //Context.LogMessage("EffiProzDB Installer Commit - Get Assembly");

                        System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(Path.Combine(path,"System.Data.EffiProzDB.dll")); 

                        xmlNode.Attributes.GetNamedItem("name").Value = "EffiProzDB Data Provider";
                        xmlNode.Attributes.GetNamedItem("invariant").Value = "System.Data.EffiProzDB";
                        xmlNode.Attributes.GetNamedItem("description").Value = ".Net Framework Data Provider for EffiProzDB";
                        xmlNode.Attributes.GetNamedItem("type").Value = "System.Data.EffiProzDB.EffiProzDBFactory, " +assembly.GetName().FullName;

                        xmlDoc.Save(xmlFileName);

                       // AssemblyCache.InstallAssembly(Path.GetFullPath("SQLite.Designer.DLL"), null, AssemblyCommitFlags.Default);

                        // Context.LogMessage("EffiProzDB Installer Commit - End");
                    }
                    catch
                    {
                        //  Context.LogMessage("EffiProzDB Installer Commit - Exception");
                    }
                   
                }
            }

            InstallDesigner();
        }
    }
}
